/* 
	Essno is an elliptic curve cryptography base software
	Popov AS, 2009
*/ 

#include <stdio.h>		// Стандартный Ввод/Вывод
#include <stdlib.h>	
#include <string.h>		// Быстрая работа с памятью memset
#include "type_ess.h"
#include "essno.h"



int initBN(BigNumber *BN){
	
   /*Значение по умолчанию длины числа*/
   if( (BN->leng_bin==0) && (BN->leng_dec==0) )
   		BN->leng_bin = BN_DEF_BIN;
   		
   /*Если указаны обе длины, завершаем работу*/
   if( (BN->leng_bin)>0 && (BN->leng_dec)>0 ){ 
		fprintf(stderr,"initBN: Неопределённость: при инициализации Большого числа указаны обе длины\n");
		exit(1);    
   };
   
   /*Если выделяют меньше 4 бит*/
   if(  (BN->leng_bin)>0 && (BN->leng_bin)<4 )
   		BN->leng_bin = BN_DEF_BIN;
   	
   /*Проверяем предельные значения длин*/
   if( 	   ((BN->leng_bin) > BN_MAX_BIN) 
   		|| ((BN->leng_dec) > BN_MAX_DEC) ){
			fprintf(stderr,"initBN: Желаемые значения Большого числа > предельных \n\t см.: BN_MAX_BIN, BN_MAX_DEC");
			exit(1);
   };
   
   /*Зависимость длины Десятичной от Двоичной (и наоборот)
    *			|MaxBin| = |MaxDec| * const 						*/
   int cgBin = 0;	// Счётчики групп, временные
   int cgDec = 0;
   if( 	(BN->leng_bin > 0) && (BN->leng_dec==0) ){
   		 cgDec = gMEM_FOR_DEC(BN, 2);
   		 cgBin =  gMEM_FOR_BIN(BN, 2);
   };
   if( 	(BN->leng_dec > 0) && (BN->leng_bin==0) ){
   		 cgDec = gMEM_FOR_DEC(BN, 10);
   		 cgBin = gMEM_FOR_BIN(BN, 10);
   };
    
   /* Выделение памяти для  групп по 32 бита */
   BN->binary = (u_int*) ess_malloc ( (int)(cgBin*4 ));

   /* Выделение памяти для  десятичных знаков (Byte) */
	BN->decimal = (u_char *) ess_malloc( cgDec );

	/*Устанавливаем макс. число bin групп*/
	BN->grp_bin_max = MAXGR_pBN_B( BN );

   /*Обнуление номеров текущих обрабатываемых групп*/
   BN->grp_bin=0;
   BN->grp_dec=0;
	
	return 0;
}

int clearBN(BigNumber *BN){
	
	/* Освобождение памяти */
	free(BN->decimal);                                   
	free(BN->binary);
	
	return 0;	
}


int synchBN(BigNumber *BN, int basis){
	
	/*Перевод двоичного числа в десятичное*/
	if( basis == 2){
		BN->grp_bin_max = MAXGR_pBN_B( BN );	//Синхр. макс. число bin групп (ДО)
		synchBN_2_to_10( BN );
		return 0;
	};
	/*Перевод десятичного числа в двоичное*/	
	if( basis == 10){
		synchBN_10_to_2( BN );
		BN->grp_bin_max = MAXGR_pBN_B( BN );	//Синхр. макс. число bin групп (ПОСЛЕ)
		return 0;		
	};
	
	/*Базис отличен от 2 или 10*/	
	fprintf(stderr,"synchBN: Ошибка синхронизации Большого числа: основание отлично от 2 или 10 \n");	
	exit(1);
	
}

/*
	Преобразование методом Горнера
*/
int	synchBN_2_to_10(BigNumber *BN){
	// Вход: указатель на участок памяти БЧ
	// Выход: двоичное число, преобразованное в десятичное (в БЧ)
	
	/*Подготовка приёмника*/
	memset(BN->decimal, 0x00, gMEM_FOR_DEC(BN,2) );
	BN->leng_dec = 0;
	BN->grp_dec = 0;
	/*Загрузка старших бит*/
	u_int BufferBits = 0;
	BN->grp_bin = BN->grp_bin_max ;			//Обработка с последней группы
	BufferBits = BN->binary [BN->grp_bin -1];

//	int i=0;
	int cbit=0;		//Счётчик обрабатываемого бита в группе
	u_int a=0;		//Старший бит в группе 
	
	/*Старшие биты сдвигаем в начало: 0011 -> 1100 */
	cbit = (BN->leng_bin)%32; 
	if(	cbit !=0 )
		BufferBits <<= 32 - cbit;
	else
		cbit = 32;
		
	/*Циклы обработки групп и битов в группе*/
	while( BN->grp_bin ){
		do{
			a = BufferBits & 0x80000000;
			if( a )
				muladdBN_dec(BN, 2, 1);	//Десятки * 2 + 1
			else
				muladdBN_dec(BN, 2, 0);
			cbit -=1;
			BufferBits <<=1;
		}while( cbit );
			
		cbit = 32;
		BN->grp_bin -= 1;
		BufferBits = (u_int)( BN->binary [BN->grp_bin -1] );
	};
	
	BN->grp_dec = 0;
		
	return 0;
}

int	synchBN_10_to_2(BigNumber *BN){
	// Вход: указатель на участок памяти БЧ
	// Выход: десятичное число, преобразованное в двоичное (в БЧ)

	/*Подготовка приёмника*/
	memset(BN->binary, 0x00, (int) (gMEM_FOR_BIN(BN,10)/4) );
	BN->leng_bin = 0;
	BN->grp_bin = 0;
	/*Копия БЧ*/
	BigNumber tempBN;
	BigNumber *tBN = &tempBN;
			
	tBN->leng_dec = BN->leng_dec;
	tBN->leng_bin = 0;
	initBN(tBN);

	memcpy(tBN->decimal, BN->decimal, tBN->leng_dec );
	
	/*Буфер бит по 32 бита*/
	u_int BufferBits=0;
   
	int cbit=32;		//Счётчик обрабатываемого бита в группе
	int a=0;		//бит для помещения в группу 
	
	/*Циклы обработки групп и битов в группе*/
	do{
		do{
			a=-1;
			a = divBN_dec(tBN, 2);	//Остаток от деления на 2
			if( a!=-1 ){
				if(a==1){
					BufferBits >>=1;
					BufferBits |= 0x80000000;
				}
				else
					BufferBits >>=1;
				
				cbit -=1;			
			};
//printf("\n a=%d, cbit=%d, BufferBits=%x", a,cbit, BufferBits);
		}while( cbit!=0 && a!=-1 );
			
		BufferBits >>= cbit;		//Выравниевание по правому краю группы
		BN->leng_bin += 32-cbit;	//Аккумулируем длину в битах
		
		cbit = 32;
		BN->binary [BN->grp_bin] =  BufferBits;
		BN->grp_bin += 1;
	}while(a != -1);
	
	/*Подготавливаем параметры БЧ*/
	BN->grp_bin_max = MAXGR_pBN_B(BN);
	BN->grp_bin = 0;
	
	clearBN(tBN);
	
	return 0;
}


int divBN_dec(BigNumber *BN, u_int ndiv){
	
	if( ndiv != 2 ){
		fprintf(stderr,"divBN_dec: умею делить только на 2 \n");	
		exit(1);
	};
	
	if(BN->leng_dec ==0)
		return -1;

	BN->grp_dec =BN->leng_dec;
	u_char CF = 0;	//Перенос из предыдущего разряда
	u_char tmp =0;	//Двоек в числе
	
	do{
		tmp = BN->decimal [BN->grp_dec -1];
		if(CF)
			tmp +=10;
			
		CF = tmp%2;					//Остаток
		tmp = (u_char) (tmp/ndiv);	//Сколько ndiv в цифре?

		BN->decimal [BN->grp_dec -1]= tmp;
		/*Старшая десятка нулевая?*/
		if(tmp==0 && (BN->grp_dec==BN->leng_dec) ){
			BN->leng_dec -=1;
		};
	
		BN->grp_dec -=1;
	}while( BN->grp_dec > 0 );
	
	BN->grp_dec = 0;
	return CF;
}


int muladdBN_dec(BigNumber *BN, u_int nmul, u_int nadd){
	
	if( nmul > 9 ){
		fprintf(stderr,"muladdBN_dec: умею умножать только на 0...9 \n");	
		exit(1);
	};
	
	if( nadd > 9 ){
		fprintf(stderr,"muladdBN_dec: умею прибавлять только 0...9 \n");	
		exit(1);
	};
//PRINT_BN(BN);
	BN->grp_dec =0;
	u_char CF = nadd;	//Перенос из предыдущего разряда
	u_char tmp =0;
	
	do{
		tmp = BN->decimal [BN->grp_dec ];
		tmp *= nmul;
		tmp += CF;

		if(tmp > 9){
			CF = (u_char) (tmp/10);
			tmp %= 10; 
		}
		else
			CF = 0;
//printf("nadd=%d, tmp=%d,  CF=%d, BN->grp_dec=%d \n", nadd,tmp,CF, BN->grp_dec);		
		BN->decimal [BN->grp_dec ] = tmp;
		BN->grp_dec += 1;
		
//printf("!!BN->decimal [BN->grp_dec ]   : %d \n", BN->decimal [BN->grp_dec ] );
	
	}while( CF || (BN->grp_dec < BN->leng_dec) );
	
//		printf("!!BN.leng_dec   : %d \n", BN->leng_dec);
	if( BN->grp_dec > BN->leng_dec) 
		BN->leng_dec = BN->grp_dec;
	
	BN->grp_dec = 0;
	
	return 0;
}


int maxBN_BN_dec(BigNumber *BN_1, BigNumber *BN_2){
	
	if( (BN_1->leng_dec) > (BN_2->leng_dec) )
		return 1;
	if( (BN_1->leng_dec) < (BN_2->leng_dec) )
		return 2;
	/*БЧ одинаковой длины*/
	int i=0;
	for(i= BN_1->leng_dec; i>0; i--){
		if( BN_1->decimal [i-1] > BN_2->decimal [i-1] ){
			return 1;
		};
		if( BN_1->decimal [i-1] < BN_2->decimal [i-1] ){
			return 2;
		};
	}; 
	
	return 0;	//БЧ одинаковой длины и равны
}

int subBN_BN_dec(BigNumber *BN_1, BigNumber *BN_2, int acc){
	// Вход: указатели: БЧ_1 - БЧ_2; Флаг акселератора(1-вкл, 0-выкл)
	// Выход: 	-Кол-во вычитаний
	//			-(x в отриц. форме) 10^(x) -сколько десятков раз вычитали 

	int tmp=0;
	tmp = maxBN_BN_dec(BN_1, BN_2);
	if( tmp==2)
		return 0;	//Вычитать не из чего: БЧ_1 < БЧ_2 
	if( tmp==0){
		memset(BN_1->decimal, 0x00, BN_1->leng_dec );
		BN_1->leng_dec = 1;
		return 1;	//Числа равны: обнуляем БЧ_1
	};
	
	/*Ускорение операции вычитания, путём умножения на 10^x*/
	int mark =0;		// Маркер "ускорителя"
//	u_char *tmas_d=NULL;		// Копия делителя * 10^x
	u_char *keep_d=NULL;		// Хранит исходный указатель БЧ_2
	u_int keep_l_d=0;	// Хранит длину БЧ_2
	u_int diff =0;		// Различие длин ()

	diff = BN_1->leng_dec - BN_2->leng_dec;  
	if( diff >1 && acc==1){
		mark =1;
		keep_d = BN_2->decimal;
		keep_l_d = BN_2->leng_dec;
		
//		tmas_d = ess_malloc( BN_1->leng_dec );
		memset( tmas_d, 0x00, BN_MAX_DEC);
		/*Можем ли вычесть из старшего разряда ? (с запасом для переноса)*/
		if( (BN_1->decimal [BN_1->leng_dec -1] -1) < (BN_2->decimal [BN_2->leng_dec -1]) )
			diff--;
			
		memcpy(tmas_d +diff, BN_2->decimal, BN_2->leng_dec );
		
		BN_2->decimal = tmas_d;
		BN_2->leng_dec = BN_2->leng_dec +diff;
		
	}
	
	/* БЧ_1 > БЧ_2 */
	int i=0, j=0;
	for(i=0; i< BN_2->leng_dec; i++ ){
		/*Вычитаем из текущего разряда, если можем*/
		if( (BN_1->decimal [i]) >= (BN_2->decimal [i]) ){
			(BN_1->decimal [i]) -= (BN_2->decimal [i]);
			/*Если его обнулили и он был старшим*/
			if( (BN_1->decimal [i])==0 && (BN_1->leng_dec -1)==i){
				BN_1->leng_dec -=1;
//printf("\nBN_1->leng_dec -=1: %d ",BN_1->leng_dec);
			};
		}
		else{
			/*Занимаем у старшего разряда единичку*/
			BN_1->decimal [i] +=10;
			BN_1->decimal [i] -= (BN_2->decimal [i]);
			
			/* Обрабатываем заём */
			j=i;
			j++;	//Следующий разряд
			/*Можем ли "занять" единицу из следующего разряда? */
			if( (BN_1->decimal [j]) >=1 ){
				BN_1->decimal [j] -=1;
				/*Если его обнулили и он был старшим*/
				if( (BN_1->decimal [j])==0 && (BN_1->leng_dec -1)==j){
					BN_1->leng_dec -=1;
//printf("\nBN_1->leng_dec -=1: %d ",BN_1->leng_dec);
				};
			}
			/*Просматриваем следующие разряды до появления цифры > 0*/
			else{
				while( BN_1->decimal [j] ==0 &&  j< (BN_1->leng_dec) ){
					BN_1->decimal [j] = 9;		//Занимаем единицы
					j++;
//	printf("\n BN_1->decimal [%d] = %d", j, BN_1->decimal [j]);
					if( (BN_1->leng_dec)==j ){
	printf("\n diff=%d", diff);
	printf("\n BN_1_DEC: ");	PRINT_BN_DEC(BN_1);	PRINT_BN(BN_1);
	printf("\n BN_2_DEC: ");	PRINT_BN_DEC(BN_2);	PRINT_BN(BN_2);	
						
						fprintf(stderr, "subBN_BN_dec: Достигли конца числа, не найдя цифры > 0\n");
						exit(1);
					};
				};
				/*Не нулевой разряд*/
				BN_1->decimal [j] -=1;
				/*Если его обнулили и он был старшим*/
				if( (BN_1->decimal [j])==0 && (BN_1->leng_dec -1)==j){
					BN_1->leng_dec -=1;
//printf("\nBN_1->leng_dec -=1: %d ",BN_1->leng_dec);
				};
			};
		};
	};
	
	/* Уходим, с учётом ускорителя */
	if( mark >0 ){
		BN_2->decimal = keep_d;
		BN_2->leng_dec = keep_l_d;
//		free(tmas_d);
		WITHOUT_0_BN_DEC( BN_1);
		return (-1)*diff;		// Возвращаем степень в которую возводили (в отриц. форме)
	};
	
	/*Убирает старшие нули для чисел вида: 11119-11108=0011*/
	WITHOUT_0_BN_DEC( BN_1);

	return 1;
}

int loadBN_decimal(BigNumber *BN, char *mas_d, int size_d ){
	// Вход: указатели БЧ, массив цифр (в прямом порядке) и длины  - 12345
	// Выход: загруженный массив цифр (в обратном порядке)- 54321

	if( size_d > BN->leng_dec ){
		fprintf(stderr,"loadBN_decimal: загружаемое десятичное число не помещается в БЧ\n");
		printf("size_d=%d > BN->leng_dec=%d   load_BN_dec=", size_d, BN->leng_dec); PRINT_BN_DEC( BN);
							int nn=0;
							for(nn=77; nn>0; nn--)
								printf("%d", BN->decimal [nn-1] );
		exit(1);
	};
		
	int i=0, j=0;
	u_char ch=0;
	for(i= size_d, j=0;  i>0;  i--, j++){
		ch = mas_d[i-1]-'0';
		if(ch>=0 && ch <= 9)
			BN->decimal[j] = ch;
		else{
			fprintf(stderr,"loadBN_decimal: Ошибка загрузки десятичного числа: цифры отличны от 0...9 \n");
			exit(1);
		};
	};	
	
	/*Если загружем число, меньшее выделенной памяти*/
	BN->leng_dec = size_d;
	/*Убирает старшие нули для чисел вида: 00123456*/
	WITHOUT_0_BN_DEC( BN);
	
	return 0;
}

int loadBN_binary(BigNumber *BN, char *mas_d, int size_d ){
	// Вход: указатели БЧ, массив цифр (в прямом порядке) и длины  - FF 61F0aE57
	// Выход: загруженный массив цифр (в обратном порядке)- 75Ea0F16 000000FF

	if( size_d*4 > BN->leng_bin ){
		fprintf(stderr,"loadBN_binary: загружаемое двоичное число не помещается в БЧ (%d > %d)\n", 4*size_d, BN->leng_bin);
		exit(1);
	};
//int t=0;
	int i=0, j=0, k=0, b=0;
	u_int buf=0;
	u_char mch[]={0,0,0,0,0,0,0,0}, ch=0;
	u_int m_hex[]={268435456, 16777216, 1048576, 65536, 4096, 256, 16, 1}; 
	for(i= size_d;  i>0;  i-=8,  b++){
		
		for(j=i, k=7; (j>i-8)&&(j>0) ; j--, k--){
			ch = mas_d[j-1];
			if( (ch >= '0') && (ch <= '9')) ch -= '0';
			if( (ch >= 'A') && (ch <= 'F')) ch = ch - 'A' + 10;
			if( (ch >= 'a') && (ch <= 'f')) ch = ch - 'a' + 10;
			if(ch>15){
				fprintf(stderr,"loadBN_binary: Ошибка загрузки десятичного числа: цифры отличны от 0...F \n");
				exit(1);
			};
			mch[ k] = ch;
		};
		
		for(k=7; k>=0; k--){
			buf += (u_int)( mch[k] * m_hex[k] );
		}

		BN->binary[ b] = buf;
		
		memset( mch, 0x00, sizeof(mch));
		buf = 0;
	};	
	
	/*Если загружем число, меньшее выделенной памяти*/
	BN->leng_bin = size_d*4;
	BN->grp_bin_max = MAXGR_pBN_B( BN);
	
	return 0;
}

int addBN_BN_dec(BigNumber *D_BN, BigNumber *S_BN, u_int sh){
	//Вход:		-указатели на Два БЧ со смещением
	//					ВНИМАНИЕ:
	// (максимальная длина приёмника должна задаваться при инициализации):
	//				 |D_BN| > |S_BN|+sh
	//Выход:	-Прибавленная последовательность	
	
	//Обнуление за пределами БЧ ( при переносе и сложении по смещению)
	int diff = 0;
	diff = D_BN->leng_dec - ( S_BN->leng_dec + sh );
	if( diff < 0 ){
		diff *= -1;
		memset( D_BN->decimal + D_BN->leng_dec, 0x00, diff ); 
	}
	else{
		D_BN->decimal [D_BN->leng_dec] = 0;
	};
	
	
	u_int i=0;
	u_char CF = 0;	//Перенос из предыдущего разряда
	u_char tmp =0;
	
	do{
		tmp = D_BN->decimal [i+sh];
		tmp += S_BN->decimal [i];
		tmp += CF;

		if(tmp > 9){
			tmp += 6;		//Переполнение
			tmp &= 0x0F;	//Младшая тетрада
			CF = 1;
		}
		else{
			CF = 0;
		};
//printf("tmp=%d, sh=%d,  CF=%d \n",tmp,sh, CF);		
		D_BN->decimal [i+sh] = tmp;
		i++;
		

//printf("!! D_BN->decimal [BN->grp_dec ]   : %d \n", D_BN->decimal [D_BN->grp_dec ] );
	
	}while( CF==1 || ( i< S_BN->leng_dec) );
	
//		printf("!! D_BN.leng_dec=%d, sh=%d \n", D_BN->leng_dec, sh);
	if( (i+sh) > D_BN->leng_dec) 
		D_BN->leng_dec = i+sh;

//		printf("=== D_BN.leng_dec=%d, sh=%d \n", D_BN->leng_dec, sh);	
	/*Убирает старшие нули для чисел вида: 00123456*/
	WITHOUT_0_BN_DEC( D_BN);
	
	return 0;
}



int mulBN_BN_dec(BigNumber *D_BN, BigNumber *BN_1, BigNumber *BN_2){
	/*Реализация умножения "в столбик"*/
	
	/*Будем умножать бОльшее БЧ на меньшее*/
	if( maxBN_BN_dec(BN_1, BN_2) ==2){
		void *t = BN_1;
		BN_1 = BN_2;
		BN_2 = t;
	};

	NULL_BN_DEC( D_BN);
	
	NULL_BN_GLOB_DEC( B_2);
	NULL_BN_GLOB_DEC( B_3);
	NULL_BN_GLOB_DEC( B_4);
	NULL_BN_GLOB_DEC( B_5);
	NULL_BN_GLOB_DEC( B_6);
	NULL_BN_GLOB_DEC( B_7);
	NULL_BN_GLOB_DEC( B_8);
	NULL_BN_GLOB_DEC( B_9);
	

	B_2->leng_dec = BN_1->leng_dec;
	/*Загружаем копии БЧ_1 в ЦИФРЫ*/		
	memcpy( B_2->decimal, BN_1->decimal, BN_1->leng_dec);
	/*Умножаем БЧ_1 на каждую цифру, имеющуюся в БЧ_2 и храним в соотв. БЧ*/
	muladdBN_dec( B_2, 2, 0);

	B_3->leng_dec = BN_1->leng_dec;
	memcpy( B_3->decimal, BN_1->decimal, BN_1->leng_dec);
	muladdBN_dec( B_3, 3, 0);
	
	B_4->leng_dec = BN_1->leng_dec;
	memcpy( B_4->decimal, BN_1->decimal, BN_1->leng_dec);
	muladdBN_dec( B_4, 4, 0);

	B_5->leng_dec = BN_1->leng_dec;
	memcpy( B_5->decimal, BN_1->decimal, BN_1->leng_dec);
	muladdBN_dec( B_5, 5, 0);

	B_6->leng_dec = BN_1->leng_dec;
	memcpy( B_6->decimal, BN_1->decimal, BN_1->leng_dec);
	muladdBN_dec( B_6, 6, 0);

	B_7->leng_dec = BN_1->leng_dec;
	memcpy( B_7->decimal, BN_1->decimal, BN_1->leng_dec);
	muladdBN_dec( B_7, 7, 0);

	B_8->leng_dec = BN_1->leng_dec;
	memcpy( B_8->decimal, BN_1->decimal, BN_1->leng_dec);
	muladdBN_dec( B_8, 8, 0);

	B_9->leng_dec = BN_1->leng_dec;
	memcpy( B_9->decimal, BN_1->decimal, BN_1->leng_dec);
	muladdBN_dec( B_9, 9, 0);

	/*Сложение со сдвигом*/
	int i=0;
	for(i=0; i< BN_2->leng_dec; i++){
		if( BN_2->decimal [i] ==0){
			continue;	//Досрочно выходим из цикла
		};
		if( BN_2->decimal [i] ==1)
			addBN_BN_dec( D_BN, BN_1, i);
		if( BN_2->decimal [i] ==2)
			addBN_BN_dec( D_BN, B_2, i);
		if( BN_2->decimal [i] ==3)
			addBN_BN_dec( D_BN, B_3, i);
		if( BN_2->decimal [i] ==4)
			addBN_BN_dec( D_BN, B_4, i);
		if( BN_2->decimal [i] ==5)
			addBN_BN_dec( D_BN, B_5, i);
		if( BN_2->decimal [i] ==6)
			addBN_BN_dec( D_BN, B_6, i);
		if( BN_2->decimal [i] ==7)
			addBN_BN_dec( D_BN, B_7, i);
		if( BN_2->decimal [i] ==8)
			addBN_BN_dec( D_BN, B_8, i);
		if( BN_2->decimal [i] ==9)
			addBN_BN_dec( D_BN, B_9, i);			
	};
	

	/*Убирает старшие нули для чисел вида: 00123456*/
	WITHOUT_0_BN_DEC( D_BN);
	
	return 0;
}


int divBN_BN_dec(BigNumber *A, BigNumber *B, BigNumber *Q, BigNumber *R){
	//Вход:	A и B в формуле: A=BQ+R
	//Выход: множитель Q и остаток R
	
	if( maxBN_BN_dec(A, B)==2){
		return -1;
	}
	
	NULL_BN_DEC( Q);
	NULL_BN_DEC( R);
	
	/*Остаток: копия A*/
	EQ_BN_BN_DEC( R, A);
	
	/*Переменная для преобразования бинарного числа в десятичное*/
	// TT
/*	BigNumber enTT_;
	  BigNumber *enTT=&enTT_;*/
/*	enTT=&enTT_;
	enTT->leng_dec =0;
	enTT->leng_bin =32;
	initBN( enTT);*/
	
	memset( enTT->binary, 0x00, gMEM_FOR_BIN( enTT, 2) );
	
	int t=0;
	/*Пока остаток R не будет меньше B */
	while(maxBN_BN_dec(R, B)!=2 ){
		t= subBN_BN_dec( R, B, 1);
		if( t<0){
			t *=-1;	//Определяем степень, в которую возводили при вычитании
			addBN_BN_dec( Q, ONE_BN, t);	//Быстрое прибавление количества вычетов из A к Q
		}
		/*При прямом вычитании*/
		else{
			enTT->binary [0] = (u_int) t;
			synchBN( enTT, 2);
			addBN_BN_dec( Q, enTT, 0);
		};
	};
	
//	clearBN( enTT);
	
	return 0;	
}

int euclidBN_BN_dec(BigNumber *A, BigNumber *B, BigNumber *X, BigNumber *Y,  BigNumber *D){
	/*Расширенный алгоритм Евклида: Ax+By=d*/
	
	/*НА ВХОДЕ: два неотрицательных числа a и b
	  НА ВЫХОДЕ: d=НОД(a,b) и целые положительные x,y: ax + by = d.
	
	1. Если b=0 положить d:=a, x:=1, y:=0 и возвратить (d,x,y)
	2. Положить x2:=1, x1:=0, y2:=0, y1:=1
	3. Пока b>0
	    3.1 q:=[a/b], r:=a-qb, x:=x2-qx1, y:=y2-qy1
	    3.2 a:=b, b:=r, x2:=x1, x1:=x, y2:=y1, y1:=y
	4. Положить d:=a, x:=x2, y:=y2 и возвратить (d,x,y)*/

	/*Копии входящих переменных*/
	NULL_BN_GLOB_DEC( ecA);
	NULL_BN_GLOB_DEC( ecB);

	EQ_BN_BN_DEC( ecA, A);
	EQ_BN_BN_DEC( ecB, B);

	NULL_BN_DEC( X);
	NULL_BN_DEC( Y);
	NULL_BN_DEC( D);

	/*Временные*/
	NULL_BN_GLOB_DEC( eT1);
	NULL_BN_GLOB_DEC( eT2);
	
	/* Будем предполагать,что  a>=b */
	int mark_ab=0;					//Маркер перестановки переменных
	if( maxBN_BN_dec(ecA, ecB) ==2){
		void *t = ecA;
		ecA = ecB;
		ecB = t;
		mark_ab=1;
	};

	/*Eсли B нулевой*/
	if( maxBN_BN_dec( ecB, NULL_BN)==0 ){
		EQ_BN_BN_DEC( D, ecA);
		
		X->leng_dec =1;
		X->decimal [0] =1;
		
		Y->leng_dec =1;
		Y->decimal [0] =0;
		
		if( mark_ab==1 ){	//Меняем переменные выхода
			EQ_BN_BN_DEC( eT1, X);
			EQ_BN_BN_DEC( X, Y);
			EQ_BN_BN_DEC( Y, eT1);
		};
		
		return 0;
	};
	
	/*Переменная, отражающая число вхождений B в A*/
	NULL_BN_GLOB_DEC( eQ);
	
	/*Остаток от вхождений */
	NULL_BN_GLOB_DEC( eR);
	
	/*	Матрица вида: 	( X2 X1 )	При инициализации:	( 1 0 )
						( Y2 Y1 ) 						( 0 1 )		*/
	
	NULL_BN_GLOB_DEC( eX1);
	eX1->leng_dec = 1;
	eX1->decimal [0] =0;
	
	NULL_BN_GLOB_DEC( eX2);
	eX2->leng_dec = 1;
	eX2->decimal [0] =1;
	
	NULL_BN_GLOB_DEC( eY1);
	eY1->leng_dec = 1;
	eY1->decimal [0] =1;

	NULL_BN_GLOB_DEC( eY2);
	eY2->leng_dec = 1;
	eY2->decimal [0] =0;
																		//  0   1   2   3   4   5
	char mSig[] = {1,1,1,1,1,1};	// показатель отрицательности (1,-1): {X1, X2, Y1, Y2, T1, T2}
	/* В реальной жизни элементы массива не принимают отрицательных значений.
	 * 		(поскольку происходит постепенная аккумуляция коэффициентов).
	 * А значит, не происходит сложения элементов разных знаков,
	 * следовательно, учачтки кода, учитывающие знак можно упразднить
	 * 		(это приведёт к незначительному ускорению за счёт сокращения числа проверок)
	 * Однако, этого не сделано в целях сохранения математической достоверности.
	 * Для определения окончательного знака используется счётчик итераций.
	 * X>=0 для первой итерации, и для всех чётных
	 * Y<0  для нечётных																	*/
	unsigned long long int Sg =0; //Маркер окончательного знака (они чередуются)
	
	while( maxBN_BN_dec( ecB, NULL_BN)==1){
		
		divBN_BN_dec( ecA, ecB, eQ, eR);
		/*Вычисляем:  T1 = X2 - X1*Q*/
		
		/* T1 = X1 * Q */
		mulBN_BN_dec( eT1, eX1, eQ);			
		
		/*Определяем знак умножения */
		if( mSig[0]==1 )
			mSig[4] =1;			// T1 >= 0
		else{
			mSig[4] =-1;				// T1 < 0
		}
		/* Вычитание с учётом знаков 					*/
		/*      T1 = (+-X2) - (+-T1):  возможны 4 случая знаков (2 случая вычислений)*/
		/*   а) X2, T1 одного знака */
		if( mSig[1]==mSig[4] ){
			addBN_BN_dec( eT1, eX2, 0); // Знак сохраняется
		}
		/*   б) X2, T1 разных знаков */
		else{
			if( maxBN_BN_dec( eX2, eT1)!=2 ){	//X2 >= T1
				subBN_BN_dec( eX2, eT1, 0);
				EQ_BN_BN_DEC( eT1, eX2);
					mSig[4] = mSig[1];		//Знак как у X2
			}
			else{							//X2 < T1
				subBN_BN_dec( eT1, eX2, 0); // Знак сохраняется (как у T1)
			};
			
		};
		
		//----------------
		/* T2 = Y1 * Q */
		mulBN_BN_dec( eT2, eY1, eQ);			
		/*Определяем знак умножения */
		if( mSig[2]==1 )
			mSig[5] =1;			// T2 >= 0
		else{
			mSig[5] =-1;				// T2 < 0
		};
		/* Вычитание с учётом знаков 					*/
		/*      T2 = (+-Y2) - (+-T2):  возможны 4 случая знаков (2 случая вычислений)*/
		/*   а) Y2, T2 одного знака */
		if( mSig[3]==mSig[5] ){
			addBN_BN_dec( eT2, eY2, 0); // Знак сохраняется
		}
		/*   б) Y2, T2 разных знаков */
		else{
			if( maxBN_BN_dec( eY2, eT2)!=2 ){	//Y2 >= T2
				subBN_BN_dec( eY2, eT2, 0);
				EQ_BN_BN_DEC( eT2, eY2);
					mSig[5] = mSig[3];		//Знак как у Y2
			}
			else{							//Y2 < T2
				subBN_BN_dec( eT2, eY2, 0); // Знак сохраняется (как у T2)
			};
			
		};
	
		
		//--------------------------------------------
		/* X2 = X1; Y2=Y1 */
		EQ_BN_BN_DEC( eX2, eX1);
		 mSig[1] = mSig[0]; 
		EQ_BN_BN_DEC( eY2, eY1);
		 mSig[3] = mSig[2]; 		
		/* X1 = T1; Y1 = T2 */
		EQ_BN_BN_DEC( eX1, eT1);
		 mSig[0] = mSig[4]; 
		EQ_BN_BN_DEC( eY1, eT2);
		 mSig[2] = mSig[5]; 		

/*printf("\n ecA: ");	PRINT_BN_DEC(ecA);
printf("   ecB: ");	PRINT_BN_DEC(ecB);
printf("   eX1: ");	PRINT_BN_DEC(eX1);
printf("   eY1: ");	PRINT_BN_DEC(eY1);
printf("   eQ: ");	PRINT_BN_DEC(eQ);
printf("   eR: ");	PRINT_BN_DEC(eR);*/

		//-------------------
		/* cA = cB; cB = R */
		EQ_BN_BN_DEC( ecA, ecB);
		EQ_BN_BN_DEC( ecB, eR);

		Sg++;
	}
	
	/* D = cA */
	EQ_BN_BN_DEC( D, ecA);
	
	/* X = X2;  Y = Y2 */
	/*Если коэффициент X,Y отрицателен, прибавляем другой модуль:
		Ax+By=d, x<0 значит x=x+B	(т.е. из модуля вычитаем коэф.)
		(Знаки чередуются)								*/
	if( Sg%2==0 || Sg==1){	//(X2 > 0) и (Y2 < 0) или (X2 == 0)
		if( maxBN_BN_dec( eX2, NULL_BN)==0){
			EQ_BN_BN_DEC( X, eX2);
			EQ_BN_BN_DEC( Y, eY2);
			}
		else{
			EQ_BN_BN_DEC( X, eX2);
			NULL_BN_DEC(Y);

			if( mark_ab==0 ){			//Противоположный модуль
				EQ_BN_BN_DEC( Y, A);
			}
			else{
				EQ_BN_BN_DEC( Y, B);
			};
			subBN_BN_dec( Y, eY2, 0);
		};
	}
	else{			//  (X2 < 0) и (Y2 > 0)
		if( mark_ab==0 ){				//Противоположный модуль
			EQ_BN_BN_DEC( X, B);
		}
		else{
			EQ_BN_BN_DEC( X, A);
		};
		subBN_BN_dec( X, eX2, 0);		
		EQ_BN_BN_DEC( Y, eY2);
	};


	if( mark_ab==1 ){	//Меняем переменные выхода
		EQ_BN_BN_DEC( eT1, X);
		EQ_BN_BN_DEC( X, Y);
		EQ_BN_BN_DEC( Y, eT1);
	};
	
	return 0;
}

int sumDot_Dot( Dot *D, Dot *Q_1, Dot *Q_2, BigNumber *p, BigNumber *a){
	
	/* L = (y2-y1) / (x2-x1) (mod p) */

/*printf("\n Q_1_x_DEC: ");	PRINT_BN_DEC(Q_1->x);
printf("\n Q_1_y_DEC: ");	PRINT_BN_DEC(Q_1->y);
printf("\n Q_2_x_DEC: ");	PRINT_BN_DEC(Q_2->x);
printf("\n Q_2_y_DEC: ");	PRINT_BN_DEC(Q_2->y);
printf("\n a_DEC: ");	PRINT_BN_DEC(a); PRINT_BN( a);*/
	NULL_BN_GLOB_DEC( LL);
	NULL_BN_GLOB_DEC( Ab);
	NULL_BN_GLOB_DEC( Bl);
	NULL_BN_GLOB_DEC( XX);
	NULL_BN_GLOB_DEC( YY);
	NULL_BN_GLOB_DEC( DD);
	
	/* Получаем лямбду L */
	/* X1 != X2 */
	if( maxBN_BN_dec( Q_1-> x, Q_2-> x )!=0 ){
		/* y2-y1 (mod p) */
		EQ_BN_BN_DEC( Ab, p);			//Находим положительное значение -y1
		 subBN_BN_dec( Ab, Q_1->y, 0);	// в его классе вычетов по модулю p
		addBN_BN_dec( Ab, Q_2->y, 0);	//Сложение
		 modBN_BN_dec( Ab, Ab, p);		// по модулю
		/* x2-x1 (mod p) */
		EQ_BN_BN_DEC( Bl, p);
		 subBN_BN_dec( Bl, Q_1->y, 0);
		addBN_BN_dec( Bl, Q_2->y, 0);
		 modBN_BN_dec( Bl, Bl, p);
		
		/* (Ab/Bl) (mod p) */
		// Обратное к Bl,	НОД(Bl,p)=1 обеспечивается простотой p
		euclidBN_BN_dec( Bl, p, XX, YY, DD);
		// L = Ab*X (mod p)
		mulBN_BN_dec( LL, Ab, XX);
		modBN_BN_dec( LL, LL, p);
	}
	else{
		/* 3*x1^2 + a (mod p) */
		mulBN_BN_dec( Ab, Q_1->x, Q_1->x);
//printf("\n Ab_DEC: ");	PRINT_BN_DEC(Ab); PRINT_BN( Ab);
		muladdBN_dec( Ab, 3, 0);
//printf("\n Ab_DEC: ");	PRINT_BN_DEC(Ab); PRINT_BN( Ab);
//printf("\n a_DEC: ");	PRINT_BN_DEC(a); PRINT_BN( a);
		addBN_BN_dec( Ab, a, 0);
//printf("\n Ab_DEC: ");	PRINT_BN_DEC(Ab); PRINT_BN( Ab);
		 modBN_BN_dec( Ab, Ab, p);
//printf("\n Ab_DEC: ");	PRINT_BN_DEC(Ab); PRINT_BN( Ab);

		/* 2*y1 */
		EQ_BN_BN_DEC( Bl, Q_1->y);		
		muladdBN_dec( Bl, 2, 0);
//printf("\n Bl_DEC: ");	PRINT_BN_DEC(Bl);

		/* (Ab/Bl) (mod p) */
		euclidBN_BN_dec( Bl, p, XX, YY, DD);
//printf("\n (Bl^-1) (mod p) XX_DEC: ");	PRINT_BN_DEC(XX);
		mulBN_BN_dec( LL, Ab, XX);
//printf("\n Ab*(Bl^-1) (mod p) LL_DEC: ");	PRINT_BN_DEC(LL);
		 modBN_BN_dec( LL, LL, p);
	};

//printf("\n ###LL_DEC: ");	PRINT_BN_DEC(LL);
	
	/* x3 = L^2 - x1 - x2 (mod p) */ 
	EQ_BN_BN_DEC( XX, p);			// p - x1
	  subBN_BN_dec( XX, Q_1->x, 0);
//printf("\n ( p-x1 ) XX_DEC: ");	PRINT_BN_DEC(XX);
	EQ_BN_BN_DEC( YY, p);			// p - x2
	  subBN_BN_dec( YY, Q_2->x, 0);
//printf("\n ( p-x2 ) YY_DEC: ");	PRINT_BN_DEC(YY);

	mulBN_BN_dec( Ab, LL, LL);		// L^2
//printf("\n (L^2) Ab_DEC: ");	PRINT_BN_DEC(Ab);
	addBN_BN_dec( Ab, XX, 0);
	addBN_BN_dec( Ab, YY, 0);		//L^2 + (p - x1) + (p - x2)

	 modBN_BN_dec( Ab, Ab, p);		//L^2 + (p - x1) + (p - x2)  (mod p)
	EQ_BN_BN_DEC( Bl, Ab);			// x3 (храним в Bl т.к. x1 ещё нужен)


	/* y3 = L * (x1 - x3) - y1  (mod p) */ 
	EQ_BN_BN_DEC( XX, p);			// p - x3
	  subBN_BN_dec( XX, Bl, 0);
//printf("\n (p - x3) XX_DEC: ");	PRINT_BN_DEC(XX);
	EQ_BN_BN_DEC( YY, p);			// p - y1
	  subBN_BN_dec( YY, Q_1->y, 0);
//printf("\n (p - y1) YY_DEC: ");	PRINT_BN_DEC(YY);
	EQ_BN_BN_DEC( Ab, Q_1->x);		
//printf("\n ------Q_1(X) Ab_DEC: ");	PRINT_BN_DEC(Ab);
	addBN_BN_dec( Ab, XX, 0);		// (x1 - x3)
//printf("\n ( x1 - x3 ) Ab_DEC: ");	PRINT_BN_DEC(Ab);
//PRINT_BN( Ab );
	
	EQ_BN_BN_DEC( D->x, Bl);		// сбрасываем x3

	mulBN_BN_dec( Bl, LL, Ab);		// L*(x1 - x3)
//printf("\n L*( x1 - x3 ) Bl_DEC: ");	PRINT_BN_DEC(Bl);
	addBN_BN_dec( Bl, YY, 0);		// L*(x1 - x3) - y1
//printf("\n L*( x1 - x3 ) - y1 Bl_DEC: ");	PRINT_BN_DEC(Bl);
	  modBN_BN_dec( Bl, Bl, p);
//printf("\n L*( x1 - x3 ) - y1 (mod p) Bl_DEC: ");	PRINT_BN_DEC(Bl);
	EQ_BN_BN_DEC( D->y, Bl);		// y3
//printf("\n (L^2 + (p - x1) + (p - x2)  (mod p)) Bl_DEC: ");	PRINT_BN_DEC(Bl);
	
	return 0;
};

int mulBN_Dot_dec( Dot *Q, BigNumber *k, Dot *P, BigNumber *p, BigNumber *a){
	/*Вход: - точка P
	 * 		- число k
	 * 		- параметры кривой 
	 *Выход: - точка Q:  Q=kP*/
	 
	 /*Бинарный алгоритм (быстрое возведение в степень)*/
	 /*А.А. Болотов с 407 +(Метод Монтгомери) */
	 
	/* Q=1*P для первого сложения*/			
	EQ_BN_BN_DEC( Q->x, P->x); 
	EQ_BN_BN_DEC( Q->y, P->y);

	 /*Представляем число k  в бинарном виде*/

	 if( maxBN_BN_dec( k, ONE_BN)==0)		// k=1
	 	return 0;
	 
	 synchBN( k, 10);
	 
	 printf("\n k-bin: "); PRINT_BN_BIN(k);
	 printf("\n k-dec: "); PRINT_BN_DEC(k);
	 PRINT_BN( k);



	/*Прибавляем остальные P к точке Q*/	
	int cbit = 0;	//Счётчик битов (степень в полиноме) (по 32 бита)
	cbit =( k->leng_bin -1)%32 ; //Начало старшего в группе
	cbit--;
	
	u_int bbuf=0;		//Хранит текущую группу
	int i=0;		//Номер обрабатываемой группы
	u_int bit=0;		//Текущий бит
	for( i = k->grp_bin_max;  i>0 ; i-- ){
		
		bbuf = k->binary[ k->grp_bin_max -1]; 
		
		for( ; cbit >=0; cbit--){
			
			bit = (bbuf<<(31-cbit))>>31 ;
			if( bit == 0)
				sumDot_Dot( Q, Q, Q, p, a);			// Q=Q+Q
			
			if( bit == 1) 
				sumDot_Dot( Q, Q, P, p, a);		// Q=Q+P
printf("\n== bit=%d ", bit);
printf("\n Qx_DEC= "); PRINT_BN_DEC( Q->x); PRINT_BN( Q->x);
printf("\n Qy_DEC= "); PRINT_BN_DEC( Q->y); PRINT_BN( Q->y);

		};
	
		cbit = 31;
	};

	return 0;	
}

int modBN_BN_dec(BigNumber *D_BN, BigNumber *S_BN, BigNumber *M_BN){
	
	EQ_BN_BN_DEC( D_BN, S_BN);

	int t=1;
	do{
		t = subBN_BN_dec( D_BN, M_BN, 1);
	}while(t!=0);
	
	WITHOUT_0_BN_DEC(D_BN);
	
	return 0;
};

void * ess_malloc( u_int leng_b){
   	void *point = NULL;
	point = malloc( leng_b ); 						
	if ( point == NULL) {										
		fprintf(stderr,"ess_malloc: Недостаточно памяти\n");					
		exit(1);													
	};															
	memset(point, 0x00, leng_b );
   
    return point;
}
